package ec.cd.processor.gui;

import info.monitorenter.gui.chart.Chart2D;
import info.monitorenter.gui.chart.ITrace2D;
import info.monitorenter.gui.chart.traces.Trace2DSimple;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.FlowLayout;
import java.awt.GridBagLayout;
import java.awt.GridLayout;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;

import ec.cd.common.Sensors;
import ec.cd.common.Sensors.SensorData;
import ec.cd.processor.TraceProcessor;
import ec.cd.processor.TraceProcessor2;

public class FrameResultsAndGraph extends JFrame {

    private JPanel contentPane;
    private JPanel graphPanel;
    private JPanel resultsPanel;
    private Chart2D graphAcc, graphGyr, graphState;
    private ITrace2D traceAccX, traceAccY, traceAccZ, traceGyrX, traceGyrY,
            traceGyrZ, traceStateAcc, traceStateGyr;
    private JLabel lblMinXAccSitting, lblMaxXAccSitting, lblMinYAccSitting,
            lblMaxYAccSitting, lblMinZAccSitting, lblMaxZAccSitting,
            lblMinXGyrSitting, lblMaxXGyrSitting, lblMinYGyrSitting,
            lblMaxYGyrSitting, lblMinZGyrSitting, lblMaxZGyrSitting,
            lblMinXAccWalking, lblMaxXAccWalking, lblMinYAccWalking,
            lblMaxYAccWalking, lblMinZAccWalking, lblMaxZAccWalking,
            lblMinXGyrWalking, lblMaxXGyrWalking, lblMinYGyrWalking,
            lblMaxYGyrWalking, lblMinZGyrWalking, lblMaxZGyrWalking,
            lblMinXAccRunning, lblMaxXAccRunning, lblMinYAccRunning,
            lblMaxYAccRunning, lblMinZAccRunning, lblMaxZAccRunning,
            lblMinXGyrRunning, lblMaxXGyrRunning, lblMinYGyrRunning,
            lblMaxYGyrRunning, lblMinZGyrRunning, lblMaxZGyrRunning;
    private JPanel panelLabelsSitting, panelLabelsWalking, panelLabelsRunning;
    private double[] rangesAcc, rangesGyr;

    // /**
    // * Launch the application.
    // */
    // public static void main(String[] args) {
    // EventQueue.invokeLater(new Runnable() {
    // public void run() {
    // try {
    // FrameResultsAndGraph frame = new FrameResultsAndGraph(0);
    // frame.setVisible(true);
    // } catch (Exception e) {
    // e.printStackTrace();
    // }
    // }
    // });
    // }
    /**
     * Create the frame.
     */
    public FrameResultsAndGraph(int runningMode, File file1, File file2,
            File file3, double q) {
        setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);
        setBounds(100, 100, 450, 300);
        contentPane = new JPanel();
        contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
        contentPane.setLayout(new GridLayout(2, 1));
        setContentPane(contentPane);

        resultsPanel = new JPanel();
        initializeGraphPanel();
        //contentPane.add(graphPanel);

        panelLabelsSitting = new JPanel();
        panelLabelsSitting.setBorder(new TitledBorder("Sitting"));
        panelLabelsWalking = new JPanel();
        panelLabelsWalking.setBorder(new TitledBorder("Walking"));
        panelLabelsRunning = new JPanel();
        panelLabelsRunning.setBorder(new TitledBorder("Running"));
        if (runningMode == 0) {// means calibration
            TraceProcessor traceProcessorSitting = new TraceProcessor();
            traceProcessorSitting.readDataFromFiles(file1);
            TraceProcessor traceProcessorWalking = new TraceProcessor();
            traceProcessorWalking.readDataFromFiles(file2);
            TraceProcessor traceProcessorRunning = new TraceProcessor();
            traceProcessorRunning.readDataFromFiles(file3);

            double[] accRangesSitting = traceProcessorSitting.getAccRanges();
            double[] accRangesWalking = traceProcessorWalking.getAccRanges();
            double[] accRangesRunning = traceProcessorRunning.getAccRanges();
            showTiltGraph(traceProcessorSitting.getAccData(), "Sitting");
            showTiltGraph(traceProcessorWalking.getAccData(), "Walking");
            showTiltGraph(traceProcessorRunning.getAccData(), "Running");

            double[] gyrRangesSitting = traceProcessorSitting.getRangesGyro();
            double[] gyrRangesWalking = traceProcessorWalking.getRangesGyro();
            double[] gyrRangesRunning = traceProcessorRunning.getRangesGyro();
            try {
                writeRanges("accRanges.txt", accRangesSitting, accRangesWalking, accRangesRunning);
                writeRanges("gyrRanges.txt", gyrRangesSitting, gyrRangesWalking, gyrRangesRunning);
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }

            initializeLabels(accRangesSitting, accRangesWalking,
                    accRangesRunning, gyrRangesSitting, gyrRangesWalking,
                    gyrRangesRunning);
            addToGraph(traceProcessorSitting.getAccData());
            addToGraph(traceProcessorSitting.getGyrData());
//            addToGraph(traceProcessorWalking.getAccData());
//            addToGraph(traceProcessorWalking.getGyrData());
//            addToGraph(traceProcessorRunning.getAccData());
//            addToGraph(traceProcessorRunning.getGyrData());
        } else {
            TraceProcessor traceProcessor = new TraceProcessor();
            TraceProcessor2 traceProcessorGyr = new TraceProcessor2();
            traceProcessor.readDataFromFiles(file1);
            traceProcessorGyr.readDataFromFiles(file1);
            try {
                readRanges(file2, file3);
            } catch (Exception ex) {
                ex.printStackTrace();
                System.exit(0);
            }

            double[] accRangesSitting = copyFromTo(rangesAcc, 0, 5);
            double[] accRangesWalking = copyFromTo(rangesAcc, 6, 11);
            double[] accRangesRunning = copyFromTo(rangesAcc, 12, 17);
            double[] gyrRangesSitting = copyFromTo(rangesGyr, 0, 5);
            double[] gyrRangesWalking = copyFromTo(rangesGyr, 6, 11);
            double[] gyrRangesRunning = copyFromTo(rangesGyr, 12, 17);
            initializeLabels(accRangesSitting, accRangesWalking, accRangesRunning, gyrRangesSitting, gyrRangesWalking, gyrRangesRunning);
            //get ranges only for X axis
            double[] rangesXAxisAcc = new double[]{rangesAcc[0], rangesAcc[1], rangesAcc[6], rangesAcc[7], rangesAcc[12], rangesAcc[13]};
            double[] rangesXAxisGyr = new double[]{rangesGyr[0], rangesGyr[1], rangesGyr[6], rangesGyr[7], rangesGyr[12], rangesGyr[13]};
            addToGraph(traceProcessor.getAccData());
            addToGraph(traceProcessor.getGyrData());
            showTiltGraph(traceProcessor.getAccData(), "Trace");
            for (q = 0; q <= 3; q += 0.01) {
                traceProcessor.getProcessingResults(traceProcessor.getAccData(), q, rangesXAxisAcc, 0);
                traceProcessorGyr.getProcessingResults(traceProcessor.getGyrData(), q, rangesXAxisGyr, 0);
            }
            
            traceProcessor.setReportedContextsGyr(traceProcessorGyr.getReportedContextsGyr());
            graphStates(traceProcessor);
        }
        contentPane.add(resultsPanel);
        //this.pack();
    }

    private void writeRanges(String fileName, double[] rangesSitting, double[] rangesWalking, double[] rangesRunning) throws IOException {
        File file = new File(fileName);
        if (!file.exists()) {
            file.createNewFile();
        }
        FileWriter fileWriter = new FileWriter(file);
        fileWriter.write("Sitting: \n");
        fileWriter.write(rangesSitting[0] + "\n");
        fileWriter.write(rangesSitting[1] + "\n");
        fileWriter.write(rangesSitting[2] + "\n");
        fileWriter.write(rangesSitting[3] + "\n");
        fileWriter.write(rangesSitting[4] + "\n");
        fileWriter.write(rangesSitting[5] + "\n");

        fileWriter.write("Walking: \n");
        fileWriter.write(rangesWalking[0] + "\n");
        fileWriter.write(rangesWalking[1] + "\n");
        fileWriter.write(rangesWalking[2] + "\n");
        fileWriter.write(rangesWalking[3] + "\n");
        fileWriter.write(rangesWalking[4] + "\n");
        fileWriter.write(rangesWalking[5] + "\n");

        fileWriter.write("Running: \n");
        fileWriter.write(rangesRunning[0] + "\n");
        fileWriter.write(rangesRunning[1] + "\n");
        fileWriter.write(rangesRunning[2] + "\n");
        fileWriter.write(rangesRunning[3] + "\n");
        fileWriter.write(rangesRunning[4] + "\n");
        fileWriter.write(rangesRunning[5] + "\n");

        fileWriter.close();
    }

    private double[] copyFromTo(double[] array, int first, int last) {
        double[] returning = new double[last - first + 1];
        int j = 0;
        for (int i = first; i <= last; i++) {
            returning[j] = array[i];
            j += 1;
        }
        return returning;
    }

    private void showTiltGraph(List<SensorData> data, String state) {
        Chart2D graphTilt = new Chart2D();
        ITrace2D traceTilt = new Trace2DSimple("Tilt");
        traceTilt.setColor(Color.RED);
        graphTilt.addTrace(traceTilt);
        int i=0;
        for (SensorData sensorData : data) {
            double x, y, z, totalAcc, tiltX, tiltY, tiltZ;
            x = sensorData.values[0];
            y = sensorData.values[1];
            z = sensorData.values[2];
            totalAcc = Math.sqrt(x * x + y * y + z * z);
            tiltX = Math.toDegrees(Math.acos(x / totalAcc));
            tiltY = Math.toDegrees(Math.acos(y / totalAcc));
            tiltZ = Math.toDegrees(Math.acos(z / totalAcc));
            if (y < 0) {
                tiltX = - tiltX;
            }
            traceTilt.addPoint(i, tiltX);
            i+=1;
        }
        JFrame frameTilt = new JFrame("Graph Tilt " + state);
        frameTilt.getContentPane().add(graphTilt);
        frameTilt.setBounds(100, 100, 450, 300);
        frameTilt.setVisible(true);
    }

    private void addToGraph(List<SensorData> data) {
        long initialTimestamp = data.get(0).timestamp;
        for (SensorData sensorData : data) {
            switch (sensorData.sensorType) {
                case Sensors.ST_ACCELEROMETER:
                    traceAccX.addPoint((sensorData.timestamp - initialTimestamp) / 1000,
                            sensorData.values[0]);
                    traceAccY.addPoint((sensorData.timestamp - initialTimestamp) / 1000,
                            sensorData.values[1]);
                    traceAccZ.addPoint((sensorData.timestamp - initialTimestamp) / 1000,
                            sensorData.values[2]);
                    break;
                case Sensors.ST_GYROSCOPE:
                    traceGyrX.addPoint((sensorData.timestamp - initialTimestamp) / 1000,
                            sensorData.values[0]);
                    traceGyrY.addPoint((sensorData.timestamp - initialTimestamp) / 1000,
                            sensorData.values[1]);
                    traceGyrZ.addPoint((sensorData.timestamp - initialTimestamp) / 1000,
                            sensorData.values[2]);
                    break;
            }
        }
    }

    private void graphStates(TraceProcessor traceProcessor) {
        List<SensorData> dataAcc = traceProcessor.getAccData();
        long initialTimestampAcc = dataAcc.get(0).timestamp;
        List<SensorData> dataGyr = traceProcessor.getAccData();
        long initialTimestampGyr = dataAcc.get(0).timestamp;
        for (int i = 0; i < dataAcc.size(); i++) {
            SensorData sensorData = dataAcc.get(i);
            int state = traceProcessor.getReportedContextsAcc().get(i);
            traceStateAcc.addPoint((sensorData.timestamp - initialTimestampAcc) / 1000, state);
        }
        for (int i = 0; i < dataGyr.size(); i++) {
            SensorData sensorData = dataAcc.get(i);
            int state = traceProcessor.getReportedContextsGyr().get(i);
            traceStateGyr.addPoint((sensorData.timestamp - initialTimestampAcc) / 1000, state);
        }
    }

    private void initializeLabels(double[] rangesAccSitting,
            double[] rangesAccWalking, double[] rangesAccRunning,
            double[] rangesGyrSitting, double[] rangesGyrWalking,
            double[] rangesGyrRunning) {
        panelLabelsSitting.setLayout(new GridLayout(6, 2));
        panelLabelsWalking.setLayout(new GridLayout(6, 2));
        panelLabelsRunning.setLayout(new GridLayout(6, 2));
        lblMinXAccSitting = new JLabel("MinXAcc: " + rangesAccSitting[0]);
        lblMaxXAccSitting = new JLabel("MaxXAcc: " + rangesAccSitting[1]);
        lblMinYAccSitting = new JLabel("MinYAcc: " + rangesAccSitting[2]);
        lblMaxYAccSitting = new JLabel("MaxYAcc: " + rangesAccSitting[3]);
        lblMinZAccSitting = new JLabel("MinZAcc: " + rangesAccSitting[4]);
        lblMaxZAccSitting = new JLabel("MaxZAcc: " + rangesAccSitting[5]);
//		System.out.println(rangesAccSitting[0]);
//		System.out.println(rangesAccSitting[1]);
//		System.out.println(rangesAccSitting[2]);
//		System.out.println(rangesAccSitting[3]);
//		System.out.println(rangesAccSitting[4]);
//		System.out.println(rangesAccSitting[5]);
        panelLabelsSitting.add(lblMinXAccSitting);
        panelLabelsSitting.add(lblMaxXAccSitting);
        panelLabelsSitting.add(lblMinYAccSitting);
        panelLabelsSitting.add(lblMaxYAccSitting);
        panelLabelsSitting.add(lblMinZAccSitting);
        panelLabelsSitting.add(lblMaxZAccSitting);
        panelLabelsSitting.setSize(200, 100);

        lblMinXAccWalking = new JLabel("MinXAcc: " + rangesAccWalking[0]);
        lblMaxXAccWalking = new JLabel("MaxXAcc: " + rangesAccWalking[1]);
        lblMinYAccWalking = new JLabel("MinYAcc: " + rangesAccWalking[2]);
        lblMaxYAccWalking = new JLabel("MaxYAcc: " + rangesAccWalking[3]);
        lblMinZAccWalking = new JLabel("MinZAcc: " + rangesAccWalking[4]);
        lblMaxZAccWalking = new JLabel("MaxZAcc: " + rangesAccWalking[5]);
//		System.out.println(rangesAccWalking[0]);
//		System.out.println(rangesAccWalking[1]);
//		System.out.println(rangesAccWalking[2]);
//		System.out.println(rangesAccWalking[3]);
//		System.out.println(rangesAccWalking[4]);
//		System.out.println(rangesAccWalking[5]);
        panelLabelsWalking.add(lblMinXAccWalking);
        panelLabelsWalking.add(lblMaxXAccWalking);
        panelLabelsWalking.add(lblMinYAccWalking);
        panelLabelsWalking.add(lblMaxYAccWalking);
        panelLabelsWalking.add(lblMinZAccWalking);
        panelLabelsWalking.add(lblMaxZAccWalking);
        panelLabelsWalking.setSize(200, 100);

        lblMinXAccRunning = new JLabel("MinXAcc: " + rangesAccRunning[0]);
        lblMaxXAccRunning = new JLabel("MaxXAcc: " + rangesAccRunning[1]);
        lblMinYAccRunning = new JLabel("MinYAcc: " + rangesAccRunning[2]);
        lblMaxYAccRunning = new JLabel("MaxYAcc: " + rangesAccRunning[3]);
        lblMinZAccRunning = new JLabel("MinZAcc: " + rangesAccRunning[4]);
        lblMaxZAccRunning = new JLabel("MaxZAcc: " + rangesAccRunning[5]);
        panelLabelsRunning.add(lblMinXAccRunning);
        panelLabelsRunning.add(lblMaxXAccRunning);
        panelLabelsRunning.add(lblMinYAccRunning);
        panelLabelsRunning.add(lblMaxYAccRunning);
        panelLabelsRunning.add(lblMinZAccRunning);
        panelLabelsRunning.add(lblMaxZAccRunning);
        panelLabelsRunning.setSize(200, 100);


        lblMinXGyrSitting = new JLabel("MinXGyr: " + rangesGyrSitting[0]);
        lblMaxXGyrSitting = new JLabel("MaxXGyr: " + rangesGyrSitting[1]);
        lblMinYGyrSitting = new JLabel("MinYGyr: " + rangesGyrSitting[2]);
        lblMaxYGyrSitting = new JLabel("MaxYGyr: " + rangesGyrSitting[3]);
        lblMinZGyrSitting = new JLabel("MinZGyr: " + rangesGyrSitting[4]);
        lblMaxZGyrSitting = new JLabel("MaxZGyr: " + rangesGyrSitting[5]);
        panelLabelsSitting.add(lblMinXGyrSitting);
        panelLabelsSitting.add(lblMaxXGyrSitting);
        panelLabelsSitting.add(lblMinYGyrSitting);
        panelLabelsSitting.add(lblMaxYGyrSitting);
        panelLabelsSitting.add(lblMinZGyrSitting);
        panelLabelsSitting.add(lblMaxZGyrSitting);

        lblMinXGyrWalking = new JLabel("MinXGyr: " + rangesGyrWalking[0]);
        lblMaxXGyrWalking = new JLabel("MaxXGyr: " + rangesGyrWalking[1]);
        lblMinYGyrWalking = new JLabel("MinYGyr: " + rangesGyrWalking[2]);
        lblMaxYGyrWalking = new JLabel("MaxYGyr: " + rangesGyrWalking[3]);
        lblMinZGyrWalking = new JLabel("MinZGyr: " + rangesGyrWalking[4]);
        lblMaxZGyrWalking = new JLabel("MaxZGyr: " + rangesGyrWalking[5]);
        panelLabelsWalking.add(lblMinXGyrWalking);
        panelLabelsWalking.add(lblMaxXGyrWalking);
        panelLabelsWalking.add(lblMinYGyrWalking);
        panelLabelsWalking.add(lblMaxYGyrWalking);
        panelLabelsWalking.add(lblMinZGyrWalking);
        panelLabelsWalking.add(lblMaxZGyrWalking);

        lblMinXGyrRunning = new JLabel("MinXGyr: " + rangesGyrRunning[0]);
        lblMaxXGyrRunning = new JLabel("MaxXGyr: " + rangesGyrRunning[1]);
        lblMinYGyrRunning = new JLabel("MinYGyr: " + rangesGyrRunning[2]);
        lblMaxYGyrRunning = new JLabel("MaxYGyr: " + rangesGyrRunning[3]);
        lblMinZGyrRunning = new JLabel("MinZGyr: " + rangesGyrRunning[4]);
        lblMaxZGyrRunning = new JLabel("MaxZGyr: " + rangesGyrRunning[5]);
        panelLabelsRunning.add(lblMinXGyrRunning);
        panelLabelsRunning.add(lblMaxXGyrRunning);
        panelLabelsRunning.add(lblMinYGyrRunning);
        panelLabelsRunning.add(lblMaxYGyrRunning);
        panelLabelsRunning.add(lblMinZGyrRunning);
        panelLabelsRunning.add(lblMaxZGyrRunning);
        resultsPanel.setLayout(new GridLayout(3, 1));
        resultsPanel.add(panelLabelsSitting);
        resultsPanel.add(panelLabelsWalking);
        resultsPanel.add(panelLabelsRunning);
    }

    private boolean readRanges(File accRangesFile, File gyrRangesFile)
            throws FileNotFoundException {
        // ToDo: read the ranges from the file if it is the case of running with
        // trace file
        FileReader fileReaderAcc = new FileReader(accRangesFile);
        FileReader fileReaderGyr = new FileReader(gyrRangesFile);
        BufferedReader readerAcc = new BufferedReader(fileReaderAcc);
        BufferedReader readerGyr = new BufferedReader(fileReaderGyr);
        try {
            rangesAcc = readRange(readerAcc);
            rangesGyr = readRange(readerGyr);
        } catch (Exception ex) {
            return false;
        }
        return true;
    }

    private double[] readRange(BufferedReader bufferedReader)
            throws IOException {
        double[] range = new double[18];
        String line;
        int i = 0;
        while ((line = bufferedReader.readLine()) != null) {
            System.out.println(line);
            String[] tockens = line.split(", ");
            for (String s : tockens) {
                try {
                    double f = Double.parseDouble(s);
                    range[i] = f;
                    i += 1;
                } catch (Exception ex) {
                }
            }
        }
        return range;
    }

    private void initializeGraphPanel() {
        graphPanel = new JPanel();
        graphAcc = new Chart2D();
        graphGyr = new Chart2D();
        graphState = new Chart2D();
        traceAccX = new Trace2DSimple();
        traceAccX.setColor(Color.RED);
        traceAccY = new Trace2DSimple();
        traceAccY.setColor(Color.BLUE);
        traceAccZ = new Trace2DSimple();
        traceAccZ.setColor(Color.GREEN);
        traceGyrX = new Trace2DSimple();
        traceGyrX.setColor(Color.RED);
        traceGyrY = new Trace2DSimple();
        traceGyrY.setColor(Color.BLUE);
        traceGyrZ = new Trace2DSimple();
        traceGyrZ.setColor(Color.GREEN);
        traceStateAcc = new Trace2DSimple();
        traceStateAcc.setColor(Color.RED);
        traceStateGyr = new Trace2DSimple();
        traceStateGyr.setColor(Color.BLUE);

        graphAcc.addTrace(traceAccX);
        graphAcc.addTrace(traceAccY);
        graphAcc.addTrace(traceAccZ);
        graphGyr.addTrace(traceGyrX);
        graphGyr.addTrace(traceGyrY);
        graphGyr.addTrace(traceGyrZ);
        graphState.addTrace(traceStateAcc);
//        graphState.addTrace(traceStateGyr);
        Chart2D graphStateGyr = new Chart2D();
        graphStateGyr.addTrace(traceStateGyr);

        JPanel panelGraphAcc = new JPanel();
        panelGraphAcc.add(graphAcc);
        JPanel panelGraphGyr = new JPanel();
        panelGraphGyr.add(graphGyr);
        JPanel panelGrapState = new JPanel();
        panelGrapState.add(graphState);
        panelGraphAcc.setSize(100, 100);
        panelGraphGyr.setSize(100, 100);
        panelGrapState.setSize(100, 100);
        graphPanel.setLayout(new GridLayout(3, 1));
        graphPanel.add(panelGraphAcc);
        graphPanel.add(panelGraphGyr);
        graphPanel.add(panelGrapState);
        graphPanel.setSize(400, 400);
        JFrame frameGraphAcc = new JFrame("Graph Acc");
        JFrame frameGraphGyr = new JFrame("Graph Gyr");
        JFrame frameGraphStateAcc = new JFrame("Graph State Acc");
        JFrame frameGraphStateGyr = new JFrame("Graph State Gyr");
        frameGraphAcc.getContentPane().add(graphAcc);
        frameGraphGyr.getContentPane().add(graphGyr);
        frameGraphStateAcc.getContentPane().add(graphState);
        frameGraphStateGyr.getContentPane().add(graphStateGyr);
        frameGraphAcc.setBounds(100, 100, 450, 300);
        frameGraphGyr.setBounds(100, 100, 450, 300);
        frameGraphStateAcc.setBounds(100, 100, 450, 300);
        frameGraphStateGyr.setBounds(100, 100, 450, 300);
        frameGraphAcc.setVisible(true);
        frameGraphGyr.setVisible(true);
        frameGraphStateAcc.setVisible(true);
        frameGraphStateGyr.setVisible(true);
    }
}
